const weFind = require('./logic/weFind');
const weMsg  = require('./logic/weMsg');
const ylog   = require('./logic/log');
const lock   = require('./logic/lock');
const db     = require('./logic/db');

const { env }   = process;
const SLICE_LEN = env.FIND_USER_NUM;
const LASTHOURS = env.LAST_HOURS;
const TASKNUM   = env.TASK_NUM;

/**
 * 检测 & 执行任务
 */
function checkExecute(){
    if(lock() > 0){
        console.log('当前有任务正在执行中...');
        return false;
    }

    let memoryUse = Math.ceil(process.memoryUsage().heapTotal/1024/1024);
    if(memoryUse > 600){
        ylog(`内存使用达到${memoryUse},自动退出重启.`,'_sys','warning');
        setTimeout(() => {
            process.exit();
        },300);
        return;
    }

    lock(1);//进入就锁防止重复查询
    let _e = 0,pNum = 0;
    db.query('select id,name,db_cof,auth_url,open_platform,is_cps,send_temp_msg from cps_platform where send_msg = 1').then(async (res) => {
        pNum = res.length;
        if(pNum){
            for(let v of res){
                if(v.db_cof){
                    try{
                        await _queryPlatformTempMsgTask(v);
                    }catch(e){
                    }
                    _e++;
                }else{
                    _e++;
                }

                if(env.DEBUG === '1'){
                    console.log(`job:${_e}===>${v.name}`);
                }
                if(pNum === _e){
                    lock(0);
                }
            }
        }else{
            lock(0);
        }
    }).catch(e => {
        console.log(e);
        lock(0);
    });
}

/**
 * 查询平台任务
 * @param {*} dbCof 
 */
function _queryPlatformTempMsgTask(dbCof){
    return new Promise(async (resolve,reject) => {
        try{
            const _dbCof = JSON.parse(dbCof.db_cof);
            let where = 'send_time < UNIX_TIMESTAMP() AND `status` = 0  AND msg_type != 1';
            if(dbCof.send_temp_msg){
                where = 'send_time < UNIX_TIMESTAMP() AND `status` = 0';
            }
            const countSql  = `SELECT count(id) AS num FROM go_task_templatemsg WHERE ${where} LIMIT 1`;
            const taskCount = await db.query(countSql,_dbCof);
            if(taskCount[0].num > 0){
                let _queryTaskSql = `select * from go_task_templatemsg where ${where} limit ${TASKNUM}`;
                const taskResult = await db.query(_queryTaskSql,_dbCof);
                if(taskResult.length){
                    let _findWeChatSql = _buildFindWechat(taskResult,dbCof.is_cps);
                    const weResult = await db.query(_findWeChatSql,_dbCof);
                    const _wechatInfoById = await _fetchWechatAccessToken(weResult,dbCof);
                    
                    for(let task of taskResult){
                        let weinfo = _wechatInfoById[task.channel_id];
                        if(weinfo.accessToken){
                            if(env.DEBUG === '1'){
                                console.log(`平台[${dbCof.name}]==>公众号[${weinfo.name}]==>任务${task.id}开始执行...`);
                            }
                            if(dbCof.is_cps){
                                const domainResult = await _findCpsDomain(_dbCof);
                                if(domainResult[0].domain){
                                    weinfo.tg_domain = domainResult[0].domain;
                                }else{
                                    ylog(`平台[${dbCof.name}]==>公众号[${weinfo.name}]获取公众号推广域名失败`,'_wechat_domain_err','warning');
                                    throw new Error('获取公众号推广域名失败');
                                }
                            }
                            await updateTaskStatus(task,0,0,dbCof);
                            await queryUserExcuteSend(task,weinfo,dbCof);
                        }else{
                            $_info = `平台[${dbCof.name}]==>公众号[${weinfo.name}]==>获取accessToken失败，任务${task.id}挂起待下次循环执行...`;
                            if(env.DEBUG === '1'){
                                console.log($_info);
                            }
                            ylog($_info,'_access_token','warning');
                        }
                    }
                    if(env.DEBUG === '1'){
                        console.log(`平台[${dbCof.name}],本轮任务执行结束...`);
                    }
                    resolve(1);
                }else{
                    resolve(0);
                }
            }else{
                resolve(0);
            }
        }catch(e){
            reject(e);
        }
    });
}

async function _findCpsDomain(dbCof){
    let _queryTaskSql = `select id,domain from go_domain where level = 2 and status = 0 order by rand() limit 1`;
    const result = await db.query(_queryTaskSql,dbCof);
    return result;
}

/**
 * 获取accesstoken
 * @param {*} weResult 
 * @param {*} dbCof 
 */
function _fetchWechatAccessToken(weResult,dbCof){
    return new Promise((resolve,reject) => {
        weFind.fetchWechatAccessToken(weResult,dbCof).then( async (accessTokenResult) => {
            const _wechatInfoById = {};
            for(let key in accessTokenResult){
                _wechatInfoById[accessTokenResult[key].id] = accessTokenResult[key];
                if(dbCof.is_cps){
                    _wechatInfoById[accessTokenResult[key].channel_id] = accessTokenResult[key];
                }
            }
            resolve(_wechatInfoById);
        }).catch(e => {
            $_info = `获取accesstoken失败，err:${JSON.stringify(e)}.`;
            if(env.DEBUG === '1'){
                console.log($_info);
            }
            ylog($_info,'_access_token','warning');
            reject(e);
        });
    });
}

/**
 * 生成查询公众号sql
 * @param {*} taskResult 
 * @param {*} isCps 
 */
function _buildFindWechat(taskResult,isCps){
    let _findWeChatWhere = [];
    for(let v of taskResult){
        if(isCps){
            _findWeChatWhere.push(`channel_id = '${v.channel_id}'`);
        }else{
            _findWeChatWhere.push(`id = ${v.channel_id}`);
        }
    }

    let _findWeChatField = 'id,name,appid,appsecret,domain';
    if(isCps){
        _findWeChatField += ',channel_id';
    }
    let _findWeChatSql = `SELECT ${_findWeChatField} FROM go_wechat WHERE (${_findWeChatWhere.join(' or ')})`;

    return _findWeChatSql;
}

/**
 * 执行任务
 * @param {*} task 
 * @param {*} weInfo 
 */
function queryUserExcuteSend(task,weInfo,dbCof){
    return new Promise((resolve,reject) => {
        let where  = buildFindUserWhere(task);
        let _field = 'uid,openid,username,book_bean';
        let userCountSql = `SELECT count(uid) as num FROM go_user WHERE ${where} LIMIT 1`;
        
        db.query(userCountSql,JSON.parse(dbCof.db_cof)).then(async(res) => {
            //console.log(`平台${dbCof.name},公众号[${weInfo.name}],任务[${task.id}],共有发送用户:${res[0].num}`);
            if(res[0].num){
                let len = SLICE_LEN;
                let sp  = Math.ceil(res[0].num / len);
                let successNum = 0;
                for(let i = 0; i <= sp; i++){
                    let start = i * len;
                    let selectUserSql = `SELECT ${_field} FROM go_user WHERE ${where} ORDER BY uid limit ${start},${len}`;
                    let zL = await _sendMsg(task,weInfo,selectUserSql,dbCof);
                    successNum += zL.success;
                }

                taskFinish(task,weInfo,res[0].num,successNum,dbCof);
                resolve(res[0].num);
            }else{
                taskFinish(task,weInfo,res[0].num,0,dbCof);
                resolve(res[0].num);
            }
        });
    });
}

/**
 * 发送消息
 * @param {*} task 
 * @param {*} weInfo 
 * @param {*} sql 
 */
function _sendMsg(task,weInfo,sql,dbCof){
    return new Promise((resolve,reject) => {
        db.query(sql,JSON.parse(dbCof.db_cof)).then(userResult => {
            let zL = {success:0,fail:0};
            const userLen = userResult.length;
            //console.log(`平台${dbCof.name},公众号[${weInfo.name}],任务[${task.id}],本次发送用户:${userLen}`);
            if(userLen){
                task.wechatInfo = weInfo;
                for(let user of userResult){
                    weMsg(task,user,dbCof.is_cps).then(res => {
                        if(env.DEBUG === '1'){
                            ylog(`发送日志：平台[${dbCof.name}],公众号[${weInfo.name}],任务[${task.id}],用户==>${user.uid}|${user.username},发送结果==>${JSON.stringify(res)}.`,'_send_log','log');
                        }
                        if(res.errcode === 0){
                            zL.success += 1;
                        }else{
                            zL.fail += 1;
                        }
                        if(userLen == zL.success + zL.fail){
                            resolve(zL);
                        }
                    }).catch(err => {
                        zL.fail += 1;
                        if(userLen == zL.success + zL.fail){
                            resolve(zL);
                        }
                    });
                }
            }else{
                resolve(zL);
            }
        });
    });
}

/**
 * 任务完成写入执行日志更改数据库任务状态
 * @param {*} task 
 * @param {*} weInfo 
 * @param {*} count 
 * @param {*} successNum 
 */
function taskFinish(task,weInfo,count,successNum,dbCof){
    let taslMsg = `平台[${dbCof.name}]==>公众号[${weInfo.name}]==>任务${task.id}发送完毕,共有发送用户：${count},其中成功发送：${successNum}`;
    if(env.DEBUG === '1'){
        console.log(taslMsg);
    }
    ylog(taslMsg,'_task','info');
    updateTaskStatus(task,count,successNum,dbCof).then(res => {
        
    });
}

/**
 * 更新任务状态
 * @param {*} task 
 * @param {*} count 
 * @param {*} successNum 
 */
function updateTaskStatus(task,count = 0,successNum = 0,dbCof){
    let now = new Date().getTime().toString().substring(0,10);
    let sql = `update go_task_templatemsg set exec_time=${now},\`status\`=1 where id=${task.id}`;
    if(count > 0){
        sql = `update go_task_templatemsg set send_user_num=${count},success_num=${successNum},task_user_num=${count},exec_num=1,\`status\`=2 where id=${task.id}`;
    }
    return new Promise((resolve,reject) => {
        db.query(sql,JSON.parse(dbCof.db_cof)).then(res => {
            if(res.changedRows){

            }
            resolve(1);
        }).catch(err => {
            
        });
    });
}

/**
 * 构造发送用户查询条件
 * @param {*} task 
 */
function buildFindUserWhere(task){
    let _cWhere = `channel_id = '${task.channel_id}' AND subscribe = 1`;
    let _tWhere = '';
    if(LASTHOURS && task.msg_type !== 1){
        _tWhere = ` AND last_access_time > (UNIX_TIMESTAMP()-${LASTHOURS}*3600)`;
    }
    if(task.fans_condition){
        if(task.fans_condition.includes('last_access_time')){
            _cWhere = `${_cWhere} ${task.fans_condition}`;
        }else{
            _cWhere = `${_cWhere} ${_tWhere} ${task.fans_condition}`;
        }
    }else{
        _cWhere = `${_cWhere} ${_tWhere}`;
    }

    return _cWhere;
}

module.exports = checkExecute;

